package com.centriole.service.workflow.service.parse;

import com.centriole.service.workflow.entity.ProParameter;
import com.centriole.service.workflow.entity.Process;
import com.centriole.service.workflow.enums.FlowNode;
import com.centriole.service.workflow.service.parse.component.*;
import com.centriole.service.workflow.util.ExpressionUtil;
import com.centriole.service.workflow.util.UserUtils;
import net.sf.json.JSONObject;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 *  封装json数据对象,将nodes,lines,properties的json数据 封装成对应集合
 *  功   能：
 *  创建人：陈默晗
 *  时   间：2018年1月4日上午10:58:02
 */
public class BpmnObject {

    private  String processId;
    private  String processName;

    private  Map<String,Node>  nodes = new HashMap<>(20);
    private Map<String,Line> lines = new HashMap<>(40);
    /***复杂节点集合:比如多任务节点、审批节点 */
    private Map<String,MultiTaskNode> complexNodes = new HashMap<>();
    /*** 真正需要被解析的连接线,合并lines和properties中含有条件的连接线,多任务节点的内部连接线不在该集合中*/
    private Map<String,String> actualLines = new ConcurrentHashMap<>();      
    /*** 从property中读取到的流程变量,静态变量 方便到 Service层中去处理 */
    private  List<ProParameter> params = new ArrayList<>(20);
    private StringBuffer bpmnXml= new StringBuffer();

    public BpmnObject(String processId, String processName) {
        this.processId = processId;
        this.processName = processName;
    }

    /**
     * 将json字符串转换成java对象
     * @param process       Process对象
     * @return  java对象
     */
    @SuppressWarnings("unchecked")
    public static BpmnObject parseToBpmnObject(Process process){
    	
        //准备集合容器和对象
        BpmnObject bpmnObject = new BpmnObject(process.getProcessKey() , process.getProcessName() );

        JSONObject jsonObject = JSONObject.fromObject( process.getBapBpmn() );
        JSONObject nodes = jsonObject.getJSONObject("nodes");
        JSONObject properties = jsonObject.getJSONObject("properties");
        JSONObject lines = jsonObject.getJSONObject("lines");
        
      //  System.out.println( process.getBapBpmn() );
        //开始解析
            //node
        nodes.keySet().forEach(e->{
            JSONObject nodeJson = nodes.getJSONObject(e.toString());
            Node node = new Node(e.toString() , nodeJson.getString("name") , nodeJson.getString("type") );
            bpmnObject.nodes.put( e.toString()  ,node   );
        });
            //line
        lines.keySet().forEach(e->{
            JSONObject lineJson = lines.getJSONObject(e.toString());
            Line line = new Line(e.toString(), lineJson.getString("name"), lineJson.getString("type")
            								,lineJson.getString("from"), lineJson.getString("to"));
            bpmnObject.lines.put( line.getFrom() + "-" + line.getTo() , line    );
        });
            //properties
        properties.keySet().forEach(e->{
            JSONObject propertyJson = properties.getJSONObject(e.toString());
            final Property p;
            //多任务节点与单任务节点需要不同的解析方式
         //   if("multiTaskOr".equals( propertyJson.getString("type") )){
            		//如果是多任务节点
            if(FlowNode.MULTI_TASK.equals( propertyJson.getString("type")  )){
                p = new Property( e.toString() , propertyJson.getString("type"));
                JSONObject tasksJson = propertyJson.getJSONObject("tasks");
                tasksJson.keySet().forEach(taskKey->{
                     Property.Task task = p.new Task(taskKey.toString(), tasksJson.getJSONObject(taskKey.toString()).getString("name"),
                    								 tasksJson.getJSONObject(taskKey.toString()).getString("radioId"),
                    								 tasksJson.getJSONObject(taskKey.toString()).getString("fkId"),
                    								 tasksJson.getJSONObject(taskKey.toString()).getString("fkType"),
                    								 tasksJson.getJSONObject(taskKey.toString()).getString("nextNodeId"),
                    								 tasksJson.getJSONObject(taskKey.toString()).get("preCondition")==null?null:tasksJson.getJSONObject(taskKey.toString()).getString("preCondition")
                    								 );
                    JSONObject conditionJson = tasksJson.getJSONObject(taskKey.toString()).getJSONObject("conditions");
                    conditionJson.keySet().forEach(con->{
                        task.getCondition().put( conditionJson.getString(con.toString()) ,con.toString()  );
                    });
                    p.getTasks().add(task);
                    bpmnObject.addProParameter(p);		//解析流程变量
                });
                	//其他
            }else{
                p = new Property(e.toString(),propertyJson.getString("radioId"), propertyJson.getString("type")
                								 ,propertyJson.getString("fkId"), propertyJson.getString("fkType")
                								 ,propertyJson.get("nextNodeId")==null?null:propertyJson.getString("nextNodeId")
                								 ,propertyJson.get("allowStop")==null?1:0,propertyJson.get("allowRecall")==null?1:0,propertyJson.get("allowHang")==null?1:0 
                								 ,propertyJson.get("agreeNodeId")==null?null:propertyJson.getString("agreeNodeId")
                								 ,propertyJson.get("disagreeNodeId")==null?null:propertyJson.getString("disagreeNodeId") 
                								);											 
                JSONObject conditionJson = propertyJson.getJSONObject("conditions");
                conditionJson.keySet().forEach(con->{
                    p.getCondition().put( conditionJson.getString(con.toString())  ,con.toString()  );
                });
                bpmnObject.addProParameter(p);		//解析 流程变量
            }
            bpmnObject.nodes.get(p.getId()).setProperty(p);
        });

        //封装 多任务节点集合 和 真正连接线集合
        bpmnObject.nodes.entrySet().stream().forEach(e->{
            final Node node = e.getValue();
            //如果该节点为多任务或者审批节点，则额外加入到complexNodes集合中
            if(FlowNode.MULTI_TASK.equals( node.getType() ) || FlowNode.EXAMINE.equals( node.getType()) ){
                MultiTaskNode multiTaskNode = new MultiTaskNode(node.getId(), node.getType(),node.getProperty().getTasks() , node.getProperty());
                bpmnObject.complexNodes.put( node.getId() , multiTaskNode);
            }
//            if(FlowNode.EXAMINE.equals( node.getType() )){
//                MultiTaskNode multiTaskNode = new ApprovalNode(node.getId(), node.getType(),node.getProperty().getTasks() , node.getProperty());
//                bpmnObject.complexNodes.put( node.getId() , multiTaskNode);
//            }
            //如果该节点存在Property属性，则额外加入到actualLines
            if(node.getProperty() != null){
                bpmnObject.actualLines.putAll( node.getProperty().getCondtionMap() );
            }
        });
        //lines中都是没有条件的连接线，需要与properties中有条件的连接线合并
        bpmnObject.lines.entrySet().parallelStream().forEach(e->{
            if( !bpmnObject.actualLines.containsKey( e.getKey() )){
                bpmnObject.actualLines.put( e.getKey() , "default" );
            }
        });

        return bpmnObject;
    }

    /**
     *  将对象解析成 activitiBPMN格式的xmlString
     */
    private void doParsing(){
        //start
        bpmnXml.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        bpmnXml.append("<definitions xmlns=\"http://www.omg.org/spec/BPMN/20100524/MODEL\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:activiti=\"http://activiti.org/bpmn\" xmlns:bpmndi=\"http://www.omg.org/spec/BPMN/20100524/DI\" xmlns:omgdc=\"http://www.omg.org/spec/DD/20100524/DC\" xmlns:omgdi=\"http://www.omg.org/spec/DD/20100524/DI\" typeLanguage=\"http://www.w3.org/2001/XMLSchema\" expressionLanguage=\"http://www.w3.org/1999/XPath\" targetNamespace=\"http://www.activiti.org/test\">");
        //设置流程id和流程名
        bpmnXml.append("<process id=\""+processId+"\" name=\""+processName+"\" isExecutable=\"true\">");
        //解析节点
         this.nodes.entrySet().parallelStream().forEach(e->{
             final Node node = e.getValue();
             //解析节点基本属性
             switch (node.getType()){
                 case FlowNode.START:
                     bpmnXml.append("<startEvent id=\""+node.getId()+"\" name=\""+node.getName()+"\"/>");
                     break;
                 case FlowNode.END:
                     bpmnXml.append("<endEvent id=\""+node.getId()+"\" name=\""+node.getName()+"\"/>");
                     break;
                 case FlowNode.USER_TASK:
                     bpmnXml.append("<userTask id=\""+node.getId()+"\" name=\""+node.getName()+"\" activiti:candidateUsers=\""+node.getProperty().getFkId()+"\"></userTask>");
                     break;
                 case FlowNode.MULTI_TASK:
                     MultiTaskNode multiTaskNode = complexNodes.get(node.getId());
                     bpmnXml.append(multiTaskNode.toBpmnString());
                     break;
                 case FlowNode.EXAMINE:
                	   MultiTaskNode apprNode = complexNodes.get(node.getId());
                       bpmnXml.append(new ApprovalNode(apprNode.getId(), apprNode.getType(), apprNode.getChildTasks(), apprNode.getProperty() ) );
                     break;
                 default:break;
             }
         });

        //解析线
        bpmnXml.append( parseLine() );
        //end
        bpmnXml.append("</process>");
        bpmnXml.append("</definitions>");
    }

    /**
     * 解析复杂(多任务节点、审批节点)节点
     * @return
     */
    public String parseComplexNode(){
        StringBuilder bpmn = new StringBuilder();
        complexNodes.entrySet().parallelStream().forEachOrdered(e->{
        	if( FlowNode.EXAMINE.equals( e.getValue().getType() )){		//如果是审批节点
        		  ApprovalNode apprNode =  new ApprovalNode(e.getValue().getId(), e.getValue().getType(), e.getValue().getChildTasks(), e.getValue().getProperty());
        		  bpmn.append( apprNode.toBpmnString() );
        	}else {		//如果是多任务节点
        		  bpmn.append( e.getValue().toBpmnString());
        	}    
        });
        return bpmn.toString();
    }
    
    /**
     * 解析外部连接线
     * @return
     */
    public String parseLine(){
        StringBuilder bpmn = new StringBuilder();
        actualLines.entrySet().parallelStream().forEachOrdered(e->{
        	if(e.getValue().contains("exit")) return;
            String[] fromTo = e.getKey().split("-");
            if( complexNodes.containsKey( fromTo[0] ) ){        //TODO:如果是 多任务节点连接到另外一个节点,则不生成对应线条,因为多任务节点内部解析会自动生成对应线条
                return;
            }
            if( !"default".equals(e.getValue()) ){
                bpmn.append(" <sequenceFlow id=\""+e.getKey()+"\" sourceRef=\""+fromTo[0]+"\" targetRef=\""+fromTo[1]+"\">" +
                        "<conditionExpression xsi:type=\"tFormalExpression\"><![CDATA[${"+e.getValue()+"}]]></conditionExpression>" +
                        "</sequenceFlow>");
            }else{
                bpmn.append("<sequenceFlow id=\""+e.getKey()+"\" sourceRef=\""+fromTo[0]+"\" targetRef=\""+fromTo[1]+"\"/>");
            }
        });
        //这里重置多任务节点内部静态变量:连接线计数器 , 以便下次解析多任务节点计数器能从0开始
        MultiTaskNode.resetLineCounter();
        return bpmn.toString();
    }

    public String getEndNodeName(){
            return null;
    }

    /**
     * 获得解析完毕的bpmnXml字符串
     * @return      String 解析完成的bpmnXml字符串
     */
    public String getBpmnXml() {
        if(StringUtils.isBlank( this.bpmnXml.toString() )){
            doParsing();
        }
        return bpmnXml.toString();
    }

    /**
     * 【2018/5/23${currentUser}】
     * 判断这个fkId 是否是 "${currentUser}" 这个字符串，如果是，则替换成当前session中保存的用户id;
     * @param fkId	String 
     * @return	String
     */

    public static String isCurrentUserAndreplace(String fkId) {
    	//if(FlowNode.CURRENT_USER.equals(fkId)) {
    	//	return UserUtils.currentUserInfo().getEmpId()+"";
    	//}
    	return fkId;
    }
    
    /**
     * 向 'pro_parameter' 表中添加流程变量
     * @param p	Property对象
     */
    public void addProParameter(Property p) {
    	p.getCondtionMap().entrySet().stream().forEach(e->{
    		if("default".equals(e.getValue())) return;		//默认条件就直接跳出
        	//基本属性设置
    		ProParameter param = new ProParameter();
        	param.setId(this.processId);
        	param.setProcessId(this.processName);
        	param.setCreateDate(param.getCreateDate()==null?new Date():param.getCreateDate());
        	param.setState("0");
        	param.setIsShow("0");
        	param.setIsJudge("0");
        	param.setNodeId(e.getKey().split("-")[0]);
        	//解析表达式,比如这种样子的: mug==1 , money>5等
        	String[] nameAndValue =  ExpressionUtil.getNameAndValue(  e.getValue() );
        	if(nameAndValue == null) return; 	//非空检查 
        	param.setParameterName(nameAndValue[0]);
        	param.setValue(nameAndValue[1]);
        	params.add(param);
    	});
    	
    	
    
    	
    }
    
    //Getter and Setter
    public Map<String, Node> getNodes() { return nodes; }
    public Map<String, Line> getLines() { return lines;}
    public Map<String, MultiTaskNode> getComplexNodes() { return complexNodes; }
    public Map<String, String> getActualLines() { return actualLines; }
	public List<ProParameter> getParams() {return params;}
	public void setParams(List<ProParameter> params) {this.params = params;}


    /*
    public static void main(String[] args) {
            String str = "{\"title\":\"${processName}\",\"nodes\":{\"demo_node_1\":{\"name\":\"开始\",\"left\":144,\"top\":202,\"type\":\"start round\",\"width\":24,\"height\":24,\"alt\":true},\"demo_node_2\":{\"name\":\"组长审批\",\"left\":279,\"top\":207,\"type\":\"userTask\",\"width\":100,\"height\":24,\"alt\":true},\"demo_node_4\":{\"name\":\"经理审批\",\"left\":498,\"top\":207,\"type\":\"userTask\",\"width\":100,\"height\":24,\"alt\":true},\"demo_node_5\":{\"name\":\"结束\",\"left\":729,\"top\":207,\"type\":\"end round\",\"width\":24,\"height\":24,\"alt\":true}},\"lines\":{\"demo_node_1_line_1\":{\"type\":\"sl\",\"from\":\"demo_node_1\",\"to\":\"demo_node_2\",\"name\":\"\"},\"demo_node_4_line_1\":{\"type\":\"sl\",\"from\":\"demo_node_4\",\"to\":\"demo_node_5\",\"name\":\"\"},\"demo_node_2_line_2\":{\"type\":\"sl\",\"from\":\"demo_node_2\",\"to\":\"demo_node_4\",\"name\":\"\"}},\"areas\":{},\"initNum\":6,\"properties\":{\"demo_node_2\":{\"radioId\":\"role\",\"type\":\"userTask\",\"fkId\":\"2,1\",\"fkType\":\"group\",\"nextNodeId\":\"demo_node_4\",\"conditions\":{\"default\":\"demo_node_4\",\"msg==next\":\"demo_node_4\"}},\"demo_node_4\":{\"radioId\":\"role\",\"type\":\"userTask\",\"fkId\":\"2,1\",\"fkType\":\"group\",\"nextNodeId\":\"demo_node_5\",\"conditions\":{\"default\":\"demo_node_5\",\"msg==ok\":\"demo_node_5\"}}}}";
            String str ="{\"title\":\"${processName}\",\"nodes\":{\"demo_node_1\":{\"name\":\"开始\",\"left\":129,\"top\":179,\"type\":\"start round\",\"width\":24,\"height\":24,\"alt\":true},\"demo_node_2\":{\"name\":\"多任务\",\"left\":261,\"top\":197,\"type\":\"multiTaskOr\",\"width\":100,\"height\":24,\"alt\":true},\"demo_node_3\":{\"name\":\"子任务1\",\"left\":431,\"top\":169,\"type\":\"userTask\",\"width\":100,\"height\":24,\"alt\":true},\"demo_node_4\":{\"name\":\"子任务2\",\"left\":429,\"top\":229,\"type\":\"userTask\",\"width\":100,\"height\":24,\"alt\":true},\"demo_node_5\":{\"name\":\"组长审阅\",\"left\":593,\"top\":205,\"type\":\"userTask\",\"width\":100,\"height\":24,\"alt\":true},\"demo_node_6\":{\"name\":\"结束\",\"left\":784,\"top\":199,\"type\":\"end round\",\"width\":24,\"height\":24,\"alt\":true}},\"lines\":{\"demo_node_1_line_1\":{\"type\":\"sl\",\"from\":\"demo_node_1\",\"to\":\"demo_node_2\",\"name\":\"\"},\"demo_node_2_line_1\":{\"type\":\"sl\",\"from\":\"demo_node_2\",\"to\":\"demo_node_3\",\"name\":\"\"},\"demo_node_3_line_1\":{\"type\":\"sl\",\"from\":\"demo_node_3\",\"to\":\"demo_node_5\",\"name\":\"\"},\"demo_node_4_line_1\":{\"type\":\"sl\",\"from\":\"demo_node_4\",\"to\":\"demo_node_5\",\"name\":\"\"},\"demo_node_5_line_1\":{\"type\":\"sl\",\"from\":\"demo_node_5\",\"to\":\"demo_node_6\",\"name\":\"\"},\"demo_node_2_line_2\":{\"type\":\"sl\",\"from\":\"demo_node_2\",\"to\":\"demo_node_4\",\"name\":\"\"}},\"areas\":{},\"initNum\":7,\"properties\":{\"demo_node_2\":{\"type\":\"multiTaskOr\",\"tasks\":{\"demo_node_2-1514430523385\":{\"radioId\":\"role\",\"fkId\":\"1,2\",\"name\":\"childTask2\",\"fkType\":\"group\",\"nextNodeId\":\"demo_node_4\",\"conditions\":{\"default\":\"demo_node_4\",\"msg==2\":\"demo_node_4\"}},\"demo_node_2-1514430547024\":{\"radioId\":\"role\",\"fkId\":\"1,2\",\"name\":\"childTask1\",\"fkType\":\"group\",\"nextNodeId\":\"demo_node_3\",\"conditions\":{\"default\":\"demo_node_3\",\"msg==1\":\"demo_node_3\"}}}},\"demo_node_3\":{\"radioId\":\"role\",\"type\":\"userTask\",\"fkId\":\"1,2\",\"fkType\":\"group\",\"nextNodeId\":\"demo_node_5\",\"conditions\":{\"default\":\"demo_node_5\"}},\"demo_node_4\":{\"radioId\":\"role\",\"type\":\"userTask\",\"fkId\":\"1,2\",\"fkType\":\"group\",\"nextNodeId\":\"demo_node_5\",\"conditions\":{\"default\":\"demo_node_5\"}},\"demo_node_5\":{\"radioId\":\"role\",\"type\":\"userTask\",\"fkId\":\"1\",\"fkType\":\"group\",\"nextNodeId\":\"demo_node_6\",\"conditions\":{\"default\":\"demo_node_6\"}}}}";
   //   多任务嵌套jsonString
            String str = "{\"title\":\"${processName}\",\"nodes\":{\"demo_node_1\":{\"name\":\"开始\",\"left\":189,\"top\":178,\"type\":\"start round\",\"width\":24,\"height\":24,\"alt\":true},\"demo_node_2\":{\"name\":\"结束\",\"left\":803,\"top\":171,\"type\":\"end round\",\"width\":24,\"height\":24,\"alt\":true},\"demo_node_3\":{\"name\":\"多任务1\",\"left\":290,\"top\":182,\"type\":\"multiTaskOr\",\"width\":100,\"height\":24,\"alt\":true},\"demo_node_4\":{\"name\":\"多任务2\",\"left\":467,\"top\":143,\"type\":\"multiTaskOr\",\"width\":100,\"height\":24,\"alt\":true},\"demo_node_6\":{\"name\":\"结果失败\",\"left\":467,\"top\":214,\"type\":\"userTask\",\"width\":100,\"height\":24,\"alt\":true},\"demo_node_7\":{\"name\":\"结果成功\",\"left\":627,\"top\":129,\"type\":\"userTask\",\"width\":100,\"height\":24,\"alt\":true}},\"lines\":{\"demo_node_3_line_1\":{\"type\":\"sl\",\"from\":\"demo_node_3\",\"to\":\"demo_node_6\",\"name\":\"\"},\"demo_node_3_line_2\":{\"type\":\"sl\",\"from\":\"demo_node_3\",\"to\":\"demo_node_4\",\"name\":\"\"},\"demo_node_4_line_1\":{\"type\":\"sl\",\"from\":\"demo_node_4\",\"to\":\"demo_node_7\",\"name\":\"\"},\"demo_node_4_line_2\":{\"type\":\"sl\",\"from\":\"demo_node_4\",\"to\":\"demo_node_6\",\"name\":\"\"},\"demo_node_7_line_1\":{\"type\":\"sl\",\"from\":\"demo_node_7\",\"to\":\"demo_node_2\",\"name\":\"\"},\"demo_node_1_line_1\":{\"type\":\"sl\",\"from\":\"demo_node_1\",\"to\":\"demo_node_3\",\"name\":\"\"},\"demo_node_6_line_1\":{\"type\":\"sl\",\"from\":\"demo_node_6\",\"to\":\"demo_node_2\",\"name\":\"\"}},\"areas\":{},\"initNum\":8,\"properties\":{\"demo_node_3\":{\"type\":\"multiTaskOr\",\"tasks\":{\"demo_node_3-1514856129055\":{\"radioId\":\"role\",\"fkId\":\"2,1\",\"name\":\"多任务1成功\",\"fkType\":\"group\",\"nextNodeId\":\"demo_node_4\",\"conditions\":{\"default\":\"demo_node_4\",\"var==1\":\"demo_node_4\"}},\"demo_node_3-1514856272033\":{\"radioId\":\"role\",\"fkId\":\"1,2\",\"name\":\"多任务1失败\",\"fkType\":\"group\",\"nextNodeId\":\"demo_node_6\",\"conditions\":{\"default\":\"demo_node_6\",\"var==0\":\"demo_node_6\"}}}},\"demo_node_4\":{\"type\":\"multiTaskOr\",\"tasks\":{\"demo_node_4-1514856129055\":{\"radioId\":\"role\",\"fkId\":\"1,2\",\"name\":\"多任务2失败\",\"fkType\":\"group\",\"nextNodeId\":\"demo_node_6\",\"conditions\":{\"default\":\"demo_node_6\",\"res==0\":\"demo_node_6\"}},\"demo_node_4-1514856272033\":{\"radioId\":\"role\",\"fkId\":\"1,2\",\"name\":\"多任务2成功\",\"fkType\":\"group\",\"nextNodeId\":\"demo_node_7\",\"conditions\":{\"default\":\"demo_node_7\",\"res==1\":\"demo_node_7\"}}}},\"demo_node_7\":{\"radioId\":\"role\",\"type\":\"userTask\",\"fkId\":\"1,2\",\"fkType\":\"group\",\"nextNodeId\":\"demo_node_2\",\"conditions\":{\"default\":\"demo_node_2\"}},\"demo_node_6\":{\"radioId\":\"role\",\"type\":\"userTask\",\"fkId\":\"1,2\",\"fkType\":\"group\",\"nextNodeId\":\"demo_node_2\",\"conditions\":{\"default\":\"demo_node_2\"}}}}";
            BpmnObject bpmnObject = BpmnObject.parseToBpmnObject("1","2",str);
            bpmnObject.getComplexNodes().entrySet().forEach(System.out::println);
    }
	*/


}
